#include "lib/pvmsystem.h"
#include "pvm/pvmapi.h"
#include "lib/pvmstrings.h"

#include <stdlib.h>
#include <stdio.h>

#include "lib/memory/pvmmemory.h"


PVMFileHandle PVMFileOpen(const pvm_char* fileName, pvm_int32 mode)
{
  pvm_char modeStr[32];
  modeStr[0] = 0;

  if(mode&PVM_READ && mode&PVM_WRITE && mode&PVM_OPEN_EXISTING)
  {
    pvm_strcpy(modeStr, _PVM_STR("r+b"));
  }
  else if(mode&PVM_READ && mode&PVM_WRITE && mode&PVM_CREATE_ALWAYS)
  {
    pvm_strcpy(modeStr, _PVM_STR("w+b"));
  }
  else if(mode&PVM_READ && mode&PVM_WRITE && mode&PVM_OPEN_ALWAYS)
  {
    pvm_strcpy(modeStr, _PVM_STR("a+b"));
  }
  else if(mode&PVM_READ && mode&PVM_OPEN_EXISTING)
  {
    pvm_strcpy(modeStr, _PVM_STR("rb"));
  }
  else if(mode&PVM_WRITE && mode&PVM_CREATE_ALWAYS)
  {
    pvm_strcpy(modeStr, _PVM_STR("wb"));
  }
  else if(mode&PVM_WRITE && mode&PVM_OPEN_ALWAYS)
  {
    pvm_strcpy(modeStr, _PVM_STR("ab"));
  }

  return fopen(fileName, modeStr);
}

void PVMFileClose(PVMFileHandle file)
{
  fclose(file);
}

pvm_bool PVMFileRead(PVMFileHandle file, void* buffer, pvm_size nBytes, pvm_size* readResult)
{
  if(readResult==NULL)
    return false;

  *readResult = 0;

  if(nBytes==0)
    return true;
  size_t res = fread(buffer, 1, nBytes, file);
  if(res!=0)
  {
    *readResult = res;
    return true;
  }
  return ferror(file)==0;
}

pvm_bool PVMFileWrite(PVMFileHandle file, void* buffer, pvm_size nBytes, pvm_size* writeResult)
{
  if(writeResult==NULL)
    return false;

  *writeResult = 0;

  if(nBytes==0)
    return true;

     size_t res = fwrite(buffer, 1, nBytes, file);

   if(res!=0)
   {
     *writeResult = res;
     return true;
   }
   else
   {
     return false;
   }
}

pvm_file_size PVMFileSize(PVMFileHandle file)
{
  pvm_file_size curOffset = PVMFileTell(file);
  if(curOffset==PVM_INVALID_FILE_SIZE)
    return PVM_INVALID_FILE_SIZE;

  if(!PVMFileSeek(file, 0, EPVM_SEEK_END))
    return PVM_INVALID_FILE_SIZE;

  pvm_file_size size = PVMFileTell(file);

  PVMFileSeek(file, curOffset, EPVM_SEEK_BEGIN);

  return size;
}

pvm_bool PVMFileSeek(PVMFileHandle file, pvm_file_size pos, pvm_int32 origin)
{
  int whence = 0;
  switch(origin)
  {
  case EPVM_SEEK_BEGIN:
    whence = SEEK_SET;
    break;
  case EPVM_SEEK_CURRENT:
    whence = SEEK_CUR;
    break;
  case EPVM_SEEK_END:
    whence = SEEK_END;
    break;
  };
#if (defined(WIN32) || defined(_WINDOWS))
  return fseek(file, pos, whence)==0;
#else
  return fseeko(file, pos, whence)==0;
#endif
}

pvm_file_size PVMFileTell(PVMFileHandle file)
{
#if (defined(WIN32) || defined(_WINDOWS))
	long offset = ftell(file);
#else
	off_t offset = ftello(file);
#endif
  if(offset==-1)
    return PVM_INVALID_FILE_SIZE;

  return offset;
}
